﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;

namespace NetAcademia.Web.Mvc.ImageRendering
{
    public static class XamlToPngHelper
    {
        #region img
        public static HtmlString XamlToPng(this HtmlHelper html, string key, object data)
        {
            return XamlToPng(html, null, null, key, data, null, null);
        }
        
        public static HtmlString XamlToPng(this HtmlHelper html, string key, object data, object sqlParameters)
        {
            return XamlToPng(html, null, null, key, data, sqlParameters, null);
        }

        public static HtmlString XamlToPng(this HtmlHelper html, string key, object data, object sqlParameters, object htmlAttributes)
        {
            return XamlToPng(html, null, null, key, data, sqlParameters, htmlAttributes);
        }

        public static HtmlString XamlToPng(this HtmlHelper html, string controller, string action, string key, object data, object sqlParameters, object htmlAttributes)
        {
            return XamlToPngHtml(html, controller, action, key, data, sqlParameters, htmlAttributes, RenderingTags.img);
        }
        #endregion

        #region linked
        public static HtmlString XamlToPngLinked(this HtmlHelper html, string key, object data, object linkRouteValues)
        {
            UrlHelper url = new UrlHelper(html.ViewContext.RequestContext, html.RouteCollection);
            string linkUrl = url.RouteUrl(linkRouteValues);
            return XamlToPngLinked(html, null, null, key, data, null, null, linkUrl);
        }

        public static HtmlString XamlToPngLinked(this HtmlHelper html, string key, object data, string linkUrl)
        {
            return XamlToPngLinked(html, null, null, key, data, null, null, linkUrl);
        }

        public static HtmlString XamlToPngLinked(this HtmlHelper html, string key, object data, object sqlParameters, object linkRouteValues)
        {
            UrlHelper url = new UrlHelper(html.ViewContext.RequestContext, html.RouteCollection);
            string linkUrl = url.RouteUrl(linkRouteValues);
            return XamlToPngLinked(html, null, null, key, data, sqlParameters, null, linkUrl);
        }

        public static HtmlString XamlToPngLinked(this HtmlHelper html, string key, object data, object sqlParameters, string linkUrl)
        {
            return XamlToPngLinked(html, null, null, key, data, sqlParameters, null, linkUrl);
        }

        public static HtmlString XamlToPngLinked(this HtmlHelper html, string key, object data, object sqlParameters, object htmlAttributes, object linkRouteValues)
        {
            UrlHelper url = new UrlHelper(html.ViewContext.RequestContext, html.RouteCollection);
            string linkUrl = url.RouteUrl(linkRouteValues);
            return XamlToPngLinked(html, null, null, key, data, sqlParameters, htmlAttributes, linkUrl);
        }

        public static HtmlString XamlToPngLinked(this HtmlHelper html, string key, object data, object sqlParameters, object htmlAttributes, string linkUrl)
        {
            return XamlToPngLinked(html, null, null, key, data, sqlParameters, htmlAttributes, linkUrl);
        }

        public static HtmlString XamlToPngLinked(this HtmlHelper html, string controller, string action, string key, object data, object sqlParameters, object htmlAttributes, object linkRouteValues)
        {
            UrlHelper url = new UrlHelper(html.ViewContext.RequestContext, html.RouteCollection);
            string linkUrl = url.RouteUrl(linkRouteValues);
            return XamlToPngHtml(html, controller, action, key, data, sqlParameters, htmlAttributes, RenderingTags.img, linkUrl);
        }

        public static HtmlString XamlToPngLinked(this HtmlHelper html, string controller, string action, string key, object data, object sqlParameters, object htmlAttributes, string linkUrl)
        {
            return XamlToPngHtml(html, controller, action, key, data, sqlParameters, htmlAttributes, RenderingTags.img, linkUrl);
        }
        #endregion


        #region input type="image"
        public static HtmlString XamlToPngInput(this HtmlHelper html, string key, object data)
        {
            return XamlToPngInput(html, null, null, key, data, null, null);
        }

        public static HtmlString XamlToPngInput(this HtmlHelper html, string key, object data, object sqlParameters)
        {
            return XamlToPngInput(html, null, null, key, data, sqlParameters, null);
        }

        public static HtmlString XamlToPngInput(this HtmlHelper html, string key, object data, object sqlParameters, object htmlAttributes)
        {
            return XamlToPngInput(html, null, null, key, data, sqlParameters, htmlAttributes);
        }

        public static HtmlString XamlToPngInput(this HtmlHelper html, string controller, string action, string key, object data, object sqlParameters, object htmlAttributes)
        {
            return XamlToPngHtml(html, controller, action, key, data, sqlParameters, htmlAttributes, RenderingTags.input);
        }
        #endregion


        #region url
        public static HtmlString XamlToPngUrl(this UrlHelper url, string key, object data)
        {
            return XamlToPngUrl(url, null, null, key, data, null);
        }

        public static HtmlString XamlToPngUrl(this UrlHelper url, string key, object data, object sqlParameters)
        {
            return XamlToPngUrl(url, null, null, key, data, sqlParameters);
        }

        public static HtmlString XamlToPngUrl(this UrlHelper url, string controller, string action, string key, object data, object sqlParameters)
        {
            return new HtmlString(GetXamlToPngUrl(url, controller, action, key, data, sqlParameters));
        }

        #endregion

        private static HtmlString XamlToPngHtml(HtmlHelper html, string controller, string action, string key, object data, object sqlParameters, object htmlAttributes, RenderingTags tag, string linkUrl = null)
        {
            UrlHelper url = new UrlHelper(html.ViewContext.RequestContext, html.RouteCollection);
            string imageUrl = GetXamlToPngUrl(url, controller, action, key, data, sqlParameters);

            return GenerateHtml(imageUrl, htmlAttributes, tag, anchorUrl: linkUrl);
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="url">Url to XAMLtoPng</param>
        /// <param name="htmlAttributes"></param>
        /// <param name="tag">a, img, input</param>
        /// <param name="text">if tag is a then this text will be its content (or the image itself if it is null) it is sensible with ..Raw family</param>
        /// <param name="anchorUrl">if tag is a then this could be the href (it is sensible only if text is null)</param>
        /// <returns></returns>
        internal static HtmlString GenerateHtml(string url, object htmlAttributes, RenderingTags tag, string text = null, string anchorUrl = null)
        {
            bool embedInAnchor = tag == RenderingTags.a;

            if (embedInAnchor)
                tag = RenderingTags.img;

            TagBuilder tagBuilder = new TagBuilder(tag.ToString());

            tagBuilder.MergeAttribute("src", url);
            if (tag == RenderingTags.input)
                tagBuilder.MergeAttribute("type", "image");

            if (embedInAnchor)
            {
                TagBuilder aTagBuilder = new TagBuilder("a");
                aTagBuilder.MergeAttribute("href", anchorUrl ?? url);

                if (string.IsNullOrWhiteSpace(text))
                    aTagBuilder.InnerHtml = tagBuilder.ToString();
                else
                    aTagBuilder.SetInnerText(text);

                tagBuilder = aTagBuilder;

            }

            if (htmlAttributes != null)
            {
                var attributes = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
                tagBuilder.MergeAttributes<string, object>(attributes, true);
            }

            return new HtmlString(tagBuilder.ToString(embedInAnchor ? TagRenderMode.Normal : TagRenderMode.SelfClosing));
        }

        private static string GetXamlToPngUrl(UrlHelper url, string controller, string action, string key, object data, object sqlParameters)
        {
            if (string.IsNullOrWhiteSpace(action))
            {
                controller = "XAMLtoMVC";
                action = "XamlToPng";
            }


            string imageUrl = url.RouteUrl(new { controller = controller, action = action, id = key });

            if (sqlParameters != null)
            {
                var attributes = HtmlHelper.AnonymousObjectToHtmlAttributes(sqlParameters);
                StringBuilder sb = new StringBuilder(attributes.Count * 30);
                
                foreach (var item in attributes)
                {
                    sb.AppendFormat("&_{0}={1}", HttpUtility.UrlEncode(item.Key), HttpUtility.UrlEncode(string.Format("{0}", item.Value)));
                }

                if (!imageUrl.Contains('?')) //már van valami a querystring-ben
                {
                    sb.Remove(0, 1);
                    sb.Insert(0, '?');
                }
                imageUrl += sb.ToString();
            }

            if (data != null)
            {
                var dataItems = HtmlHelper.AnonymousObjectToHtmlAttributes(data);
                StringBuilder sb = new StringBuilder(dataItems.Count * 30);
                
                foreach (var item in dataItems)
                {
                    sb.AppendFormat("&{0}={1}", HttpUtility.UrlEncode(item.Key), HttpUtility.UrlEncode(string.Format("{0}", item.Value)));
                }

                if (!imageUrl.Contains('?')) //már van valami a querystring-ben
                {
                    sb.Remove(0, 1);
                    sb.Insert(0, '?');
                }
                imageUrl += sb.ToString();
            }

            return imageUrl;
        }
    }

    enum RenderingTags
    {
        img,
        input,
        a
    }
}
